
/*++

Copyright (c) 1990-2003  Microsoft Corporation


Module Name:

    escape.c


Abstract:

   This module contains the code to implement the DrvEscape() driver call


Author:

    15:30 on Mon 06 Dec 1993    
        Created it


[Environment:]

    GDI Device Driver - Plotter.


[Notes:]


Revision History:


--*/

#include "precomp.h"
#pragma hdrstop

#define DBG_PLOTFILENAME    DbgEscape

#define DBG_DRVESCAPE         0x00000001


DEFINE_DBGVAR(0);



#define pbIn     ((BYTE *)pvIn)
#define pdwIn    ((DWORD *)pvIn)
#define pdwOut   ((DWORD *)pvOut)



ULONG
DrvEscape(
                        __in SURFOBJ *pso,
                        ULONG   iEsc,
                        ULONG   cjIn,
    __in_bcount(cjIn)   PVOID   pvIn,
                        ULONG   cjOut,
    __out_bcount(cjOut) PVOID   pvOut
)

/*++

Routine Description:

    Performs the escape functions.  Currently,  only 3 are defined -
    one to query the escapes supported,  the other for raw data, and the
    last for setting the COPYCOUNT.


Arguments:

    pso     - The surface object interested

    iEsc    - The function requested

    cjIn    - Number of bytes in the following

    pvIn    - Location of input data

    cjOut   - Number of bytes in the following

    pvOut   - Location of output area


Return Value:

    ULONG depends on the escape


Author:

    05-Jul-1996 Fri 13:18:54 created  
        Re-write comment, and fix the PASSTHROUGH problem

Revision History:


--*/

{
    ULONG   ulRes;
    PPDEV   pPDev;
    DWORD   cbWritten;


    UNREFERENCED_PARAMETER( cjOut );
    UNREFERENCED_PARAMETER( pvOut );


    if (!(pPDev = SURFOBJ_GETPDEV(pso))) {

        PLOTERR(("DrvEscape: Invalid pPDev"));
        return(FALSE);
    }

    ulRes = 0;                 /*  Return failure,  by default */

    switch (iEsc) {

    case QUERYESCSUPPORT:

        PLOTDBG(DBG_DRVESCAPE, ("DrvEscape: in QUERYESCAPESUPPORT"));

        if ((cjIn == 4) && (pvIn)) {

            //
            // Data may be valid,  so check for supported function
            //

            switch (*pdwIn) {

            case QUERYESCSUPPORT:
            case PASSTHROUGH:

                ulRes = 1;                 /* ALWAYS supported */
                break;

            case SETCOPYCOUNT:

                //
                // if the target device actually allows us to tell it
                // how many copies to print of a document, then pass
                // that information back to the caller.
                //

                if (pPDev->pPlotGPC->MaxCopies > 1) {

                    ulRes = 1;
                }

                break;
            }
        }

        break;

    case PASSTHROUGH:

        PLOTDBG(DBG_DRVESCAPE, ("DrvEscape: in PASSTHROUGH"));

        //
        // 05-Jul-1996 Fri 12:59:31 updated  
        //
        // This simply passes the RAW data to the target device, untouched.
        //
        // Win 3.1 actually uses the first 2 bytes as a count of the number of
        // bytes that follow!  So we will check if cjIn represents more data
        // than the first WORD of pvIn
        //

        if (EngCheckAbort(pPDev->pso)) {

            //
            // Set the cancel DOC flag
            //

            pPDev->Flags |= PDEVF_CANCEL_JOB;

            PLOTERR(("DrvEscape(PASSTHROUGH): Job Canceled"));

        } else if ((cjIn <= sizeof(WORD)) || (pvIn == NULL)) {

            SetLastError(ERROR_INVALID_PARAMETER);

            PLOTERR(("DrvEscape(PASSTHROUGH): cjIn <= 2 or pvIn=NULL, nothing to output"));

        } else {

            union {
                WORD    wCount;
                BYTE    bCount[2];
            } u;

            u.bCount[0] = pbIn[0];
            u.bCount[1] = pbIn[1];
            cbWritten   = 0;

            if ((u.wCount == 0) ||
                ((cjIn - sizeof(WORD)) < (DWORD)u.wCount)) {

                PLOTERR(("DrvEscape(PASSTHROUGH): cjIn to small OR wCount is zero/too big"));

                SetLastError(ERROR_INVALID_DATA);

            } else if ((WritePrinter(pPDev->hPrinter,
                                        (LPVOID)(pbIn + 2),
                                        (DWORD)u.wCount,
                                        &cbWritten))    &&
                       ((DWORD)u.wCount == cbWritten)) {

                ulRes = (DWORD)u.wCount;

            } else {

                PLOTERR(("DrvEscape(PASSTHROUGH): WritePrinter() FAILED, cbWritten=%ld bytes",
                            cbWritten));
            }
        }

        break;

    case SETCOPYCOUNT:

        //
        // Input data is a DWORD count of copies
        //

        PLOTDBG(DBG_DRVESCAPE, ("DrvEscape: in SETCOPYCOUNT"));

        if ((pdwIn) && (*pdwIn)) {

            //
            // Load the value of current copies since we will, and Check that
            // is within the printers range,  and truncate if it is not.
            // The device information structure, tells us the maximum amount
            // of copies the device can generate on its own. We save this new
            // Copy amount inside of our current DEVMODE that we have stored,
            // as part of our PDEV. The copy count actually gets output
            // later to the target device.
            //

            pPDev->PlotDM.dm.dmCopies = (SHORT)*pdwIn;

            if ((WORD)pPDev->PlotDM.dm.dmCopies > pPDev->pPlotGPC->MaxCopies) {

               pPDev->PlotDM.dm.dmCopies = (SHORT)pPDev->pPlotGPC->MaxCopies;
            }

            if ((pdwOut) && (cjOut)) {

                cbWritten = (DWORD)pPDev->PlotDM.dm.dmCopies;

                CopyMemory(pdwOut,
                           &cbWritten,
                           (cjOut >= sizeof(DWORD)) ? sizeof(DWORD) : cjOut);
            }


            //
            // Success!
            //

            ulRes = 1;
        }

        break;

    default:

        PLOTERR(("DrvEscape: Unsupported Escape Code : %d\n", iEsc ));

        SetLastError(ERROR_INVALID_FUNCTION);
        break;
    }

    return(ulRes);
}

